using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;

namespace 控制台编码切换器
{
    public partial class MainForm : Form
    {
        // API导入
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool SetConsoleCP(uint wCodePageID);
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool SetConsoleOutputCP(uint wCodePageID);
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern uint GetConsoleOutputCP();
        [DllImport("kernel32.dll")]
        private static extern uint GetSystemDefaultOemCodePage();

        // 控件定义（新增自动去除BOM复选框）
        private readonly Button _btnGbk;
        private readonly Button _btnUtf8;
        private readonly Button _btnRestore;
        private readonly CheckBox _chkPermanent;
        private readonly Label _lblCurrent;
        private readonly TextBox _logBox; // 运行日志窗口
        private readonly Button _btnSelectBat;
        private readonly TextBox _txtBatPath;
        private readonly ComboBox _comboRunMode;
        private readonly Button _btnRunBat;
        private readonly Button _btnSelectExe;
        private readonly TextBox _txtExePath;
        private readonly TextBox _txtExeArgs;
        private readonly Button _btnRunExe;
        private readonly CheckBox _chkAutoRemoveBom; // 新增：自动去除BOM复选框

        public MainForm()
        {
            // 基础窗口设置
            Text = "控制台编码切换器（带BOM处理）";
            Width = 850;
            Height = 820; // 增加高度容纳新控件
            StartPosition = FormStartPosition.CenterScreen;
            FormBorderStyle = FormBorderStyle.Sizable;
            MaximizeBox = true;
            MinimumSize = new Size(800, 640);
            Font = new Font("Microsoft YaHei UI", 10f, FontStyle.Regular);
            BackColor = Color.FromArgb(248, 249, 250);

            // 主布局：7行表格布局（新增BOM复选框行）
            var mainLayout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                ColumnCount = 1,
                RowCount = 7, // 原为6行，新增1行用于BOM复选框
                Padding = new Padding(15),
                BackColor = Color.Transparent
            };
            mainLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f));
            mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); // 当前编码标签
            mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); // 顶部按钮行
            mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); // 永久生效复选框
            mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); // 新增：BOM复选框行
            mainLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 100f)); // 日志框
            mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); // BAT区域
            mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); // EXE区域
            Controls.Add(mainLayout);

            #region 1. 当前控制台编码标签
            _lblCurrent = new Label
            {
                Text = "当前控制台编码：",
                AutoSize = true,
                Margin = new Padding(0, 10, 0, 12),
                Font = new Font("Microsoft YaHei UI", 10.5f, FontStyle.Bold),
                ForeColor = Color.FromArgb(33, 74, 130),
                BackColor = Color.Transparent
            };
            mainLayout.Controls.Add(_lblCurrent, 0, 0);
            #endregion

            #region 2. 顶部按钮行
            var topButtonsLayout = new TableLayoutPanel
            {
                Dock = DockStyle.Top,
                ColumnCount = 3,
                AutoSize = true,
                Margin = new Padding(0, 0, 0, 15),
                Padding = new Padding(5),
                BackColor = Color.Transparent,
                ColumnStyles =
                {
                    new ColumnStyle(SizeType.Percent, 33.33f),
                    new ColumnStyle(SizeType.Percent, 33.33f),
                    new ColumnStyle(SizeType.Percent, 33.34f)
                }
            };

            _btnGbk = CreateStyledButton("切换到 GBK (936)");
            _btnGbk.Margin = new Padding(4, 0, 4, 0);
            _btnGbk.Click += (_, __) => SetCp(936);
            _btnGbk.Dock = DockStyle.Fill;
            topButtonsLayout.Controls.Add(_btnGbk, 0, 0);

            _btnUtf8 = CreateStyledButton("切换到 UTF-8 (65001)");
            _btnUtf8.Margin = new Padding(4, 0, 4, 0);
            _btnUtf8.Click += (_, __) => SetCp(65001);
            _btnUtf8.Dock = DockStyle.Fill;
            topButtonsLayout.Controls.Add(_btnUtf8, 1, 0);

            _btnRestore = CreateStyledButton("还原默认编码");
            _btnRestore.Margin = new Padding(4, 0, 4, 0);
            _btnRestore.Click += (_, __) => RestoreDefault();
            _btnRestore.Dock = DockStyle.Fill;
            topButtonsLayout.Controls.Add(_btnRestore, 2, 0);
            mainLayout.Controls.Add(topButtonsLayout, 0, 1);
            #endregion

            #region 3. 永久生效复选框
            _chkPermanent = new CheckBox
            {
                Text = "永久生效（写入注册表，新窗口默认使用当前编码）",
                AutoSize = true,
                Margin = new Padding(0, 0, 0, 10),
                FlatStyle = FlatStyle.Flat,
                Font = new Font("Microsoft YaHei UI", 9.5f),
                ForeColor = Color.FromArgb(60, 60, 60),
                BackColor = Color.Transparent,
                FlatAppearance = { CheckedBackColor = Color.Transparent }
            };
            mainLayout.Controls.Add(_chkPermanent, 0, 2);
            #endregion

            #region 4. 自动去除BOM复选框（核心新增控件）
            _chkAutoRemoveBom = new CheckBox
            {
                Text = "自动去除BAT文件BOM头（运行前检测并移除UTF-8 BOM）",
                AutoSize = true,
                Margin = new Padding(0, 0, 0, 15),
                FlatStyle = FlatStyle.Flat,
                Font = new Font("Microsoft YaHei UI", 9.5f),
                ForeColor = Color.FromArgb(220, 53, 69), // 红色突出显示
                BackColor = Color.Transparent,
                FlatAppearance = { CheckedBackColor = Color.Transparent },
                Checked = true // 默认启用
            };
            mainLayout.Controls.Add(_chkAutoRemoveBom, 0, 3); // 放在新增的行
            #endregion

            #region 5. 运行日志窗口（优化后）
            _logBox = new TextBox
            {
                Multiline = true,
                ScrollBars = ScrollBars.Vertical,
                ReadOnly = true,
                BackColor = Color.White,
                BorderStyle = BorderStyle.FixedSingle,
                Font = new Font("Consolas", 9f),
                Dock = DockStyle.Fill,
                Margin = new Padding(0, 0, 0, 15),
                Padding = new Padding(8, 8, 8, 8)
            };
            mainLayout.Controls.Add(_logBox, 0, 4);
            #endregion

            #region 6. BAT文件选择区域
            var batGroup = new GroupBox
            {
                Text = "运行批处理文件",
                Dock = DockStyle.Top,
                Margin = new Padding(0, 0, 0, 15),
                Height = 130,
                FlatStyle = FlatStyle.Flat,
                ForeColor = Color.FromArgb(50, 70, 90),
                Padding = new Padding(15, 20, 15, 15),
                BackColor = Color.Transparent
            };
            mainLayout.Controls.Add(batGroup, 0, 5);

            _btnSelectBat = CreateStyledButton("选择 BAT 文件");
            _btnSelectBat.Location = new Point(10, 20);
            _btnSelectBat.Size = new Size(120, 34);
            _btnSelectBat.Anchor = AnchorStyles.Top | AnchorStyles.Left;
            batGroup.Controls.Add(_btnSelectBat);

            _txtBatPath = new TextBox
            {
                Left = 140,
                Top = 20,
                ReadOnly = true,
                BackColor = Color.White,
                BorderStyle = BorderStyle.FixedSingle,
                Font = new Font("Microsoft YaHei UI", 9.5f),
                Padding = new Padding(5)
            };
            _txtBatPath.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
            _txtBatPath.Width = batGroup.Width - 150;
            batGroup.Controls.Add(_txtBatPath);

            _comboRunMode = new ComboBox
            {
                Left = 10,
                Top = 70,
                Width = 220,
                DropDownStyle = ComboBoxStyle.DropDownList,
                FlatStyle = FlatStyle.Flat,
                BackColor = Color.White,
                Font = new Font("Microsoft YaHei UI", 9.5f)
            };
            _comboRunMode.Items.AddRange(new string[] { "使用 cmd.exe", "使用 Windows Terminal" });
            _comboRunMode.SelectedIndex = 0;
            _comboRunMode.Anchor = AnchorStyles.Top | AnchorStyles.Left;
            batGroup.Controls.Add(_comboRunMode);

            _btnRunBat = CreateStyledButton("运行 BAT");
            _btnRunBat.Location = new Point(240, 70);
            _btnRunBat.Size = new Size(100, 34);
            _btnRunBat.Anchor = AnchorStyles.Top | AnchorStyles.Left;
            batGroup.Controls.Add(_btnRunBat);
            #endregion

            #region 7. EXE文件选择区域
            var exeGroup = new GroupBox
            {
                Text = "运行带控制台的 EXE 程序",
                Dock = DockStyle.Top,
                Margin = new Padding(0, 0, 0, 15),
                Height = 140,
                FlatStyle = FlatStyle.Flat,
                ForeColor = Color.FromArgb(50, 70, 90),
                Padding = new Padding(15, 20, 15, 15),
                BackColor = Color.Transparent
            };
            mainLayout.Controls.Add(exeGroup, 0, 6);

            _btnSelectExe = CreateStyledButton("选择 EXE 文件");
            _btnSelectExe.Location = new Point(10, 20);
            _btnSelectExe.Size = new Size(120, 34);
            _btnSelectExe.Anchor = AnchorStyles.Top | AnchorStyles.Left;
            exeGroup.Controls.Add(_btnSelectExe);

            _txtExePath = new TextBox
            {
                Left = 140,
                Top = 20,
                ReadOnly = true,
                BackColor = Color.White,
                BorderStyle = BorderStyle.FixedSingle,
                Font = new Font("Microsoft YaHei UI", 9.5f),
                Padding = new Padding(5)
            };
            _txtExePath.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
            _txtExePath.Width = exeGroup.Width - 150;
            exeGroup.Controls.Add(_txtExePath);

            var argsLabel = new Label
            {
                Text = "命令行参数：",
                Left = 10,
                Top = 70,
                Width = 120,
                TextAlign = ContentAlignment.MiddleLeft,
                ForeColor = Color.FromArgb(50, 70, 90),
                BackColor = Color.Transparent
            };
            argsLabel.Anchor = AnchorStyles.Top | AnchorStyles.Left;
            exeGroup.Controls.Add(argsLabel);

            _txtExeArgs = new TextBox
            {
                Left = 140,
                Top = 70,
                BackColor = Color.White,
                BorderStyle = BorderStyle.FixedSingle,
                Font = new Font("Microsoft YaHei UI", 9.5f),
                Padding = new Padding(5)
            };
            _txtExeArgs.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
            _txtExeArgs.Width = exeGroup.Width - 350;
            exeGroup.Controls.Add(_txtExeArgs);

            _btnRunExe = CreateStyledButton("运行 EXE");
            _btnRunExe.Location = new Point(exeGroup.Width - 130, 70);
            _btnRunExe.Size = new Size(100, 34);
            _btnRunExe.Anchor = AnchorStyles.Top | AnchorStyles.Right;
            exeGroup.Controls.Add(_btnRunExe);
            #endregion

            #region 窗口大小变化适配
            batGroup.Resize += (s, e) =>
            {
                _txtBatPath.Width = batGroup.Width - 150;
            };
            exeGroup.Resize += (s, e) =>
            {
                _txtExePath.Width = exeGroup.Width - 150;
                _txtExeArgs.Width = exeGroup.Width - 350;
                _btnRunExe.Location = new Point(exeGroup.Width - 130, 70);
            };
            #endregion

            #region 事件绑定
            _btnSelectBat.Click += (_, __) => SelectBatFile();
            _btnRunBat.Click += (_, __) => RunBatFile(); // 核心修改：运行BAT前处理BOM
            _btnSelectExe.Click += (_, __) => SelectExeFile();
            _btnRunExe.Click += (_, __) => RunExeFile();
            #endregion

            // 初始化显示当前编码
            RefreshCurrent();
        }

        #region 控件样式方法
        private Button CreateStyledButton(string text)
        {
            return new Button
            {
                Text = text,
                FlatStyle = FlatStyle.Flat,
                BackColor = Color.FromArgb(52, 120, 243),
                ForeColor = Color.White,
                Cursor = Cursors.Hand,
                FlatAppearance = { BorderSize = 0 },
                Padding = new Padding(8),
                Height = 34,
                Font = new Font("Microsoft YaHei UI", 10f, FontStyle.Regular),
                AutoSize = true
            };
        }
        #endregion

        #region 文件选择与运行方法（核心修改部分）
        // 选择BAT文件
        private void SelectBatFile()
        {
            using var ofd = new OpenFileDialog
            {
                Filter = "Batch Files (*.bat)|*.bat|All Files (*.*)|*.*",
                Title = "选择批处理文件"
            };
            if (ofd.ShowDialog() == DialogResult.OK)
                _txtBatPath.Text = ofd.FileName;
        }

        // 运行BAT文件（核心修改：增加BOM检测和移除逻辑）
        private void RunBatFile()
        {
            if (string.IsNullOrWhiteSpace(_txtBatPath.Text) || !File.Exists(_txtBatPath.Text))
            {
                Log("⚠️ 请先选择有效的 BAT 文件");
                return;
            }

            // 新增：自动去除BOM处理（如果启用）
            if (_chkAutoRemoveBom.Checked)
            {
                bool bomRemoved = Utils.RemoveBomFromFile(_txtBatPath.Text);
                if (bomRemoved)
                {
                    Log($"✅ 已移除BAT文件的UTF-8 BOM头：{Path.GetFileName(_txtBatPath.Text)}");
                }
                else
                {
                    Log($"ℹ️ BAT文件无UTF-8 BOM头，无需处理：{Path.GetFileName(_txtBatPath.Text)}");
                }
            }
            else
            {
                Log($"ℹ️ 自动去除BOM功能已关闭，直接运行BAT文件：{Path.GetFileName(_txtBatPath.Text)}");
            }

            // 原有运行逻辑
            bool useTerminal = _comboRunMode.SelectedIndex == 1;
            try
            {
                var psi = new ProcessStartInfo
                {
                    UseShellExecute = true
                };

                string batFilePath = _txtBatPath.Text.Replace("\"", "\\\"");

                if (useTerminal && IsWindowsTerminalAvailable())
                {
                    psi.FileName = "wt.exe";
                    psi.Arguments = $"new-tab --title \"运行批处理：{Path.GetFileName(_txtBatPath.Text)}\" -- cmd.exe /k \"chcp {Console.OutputEncoding.CodePage} && \"{batFilePath}\"\"";
                }
                else
                {
                    psi.FileName = "cmd.exe";
                    psi.Arguments = $"/k \"chcp {Console.OutputEncoding.CodePage} && \"{batFilePath}\"\"";
                }

                Process.Start(psi);
                Log($"🚀 已启动 {Path.GetFileName(_txtBatPath.Text)}（{_comboRunMode.Text}）");
            }
            catch (Exception ex)
            {
                Log($"❌ 运行BAT错误：{ex.Message}");
                if (useTerminal)
                {
                    Log("💡 提示：如果Windows Terminal不可用，请尝试选择'使用cmd.exe'选项");
                }
            }
        }

        /// <summary>
        /// 检查Windows Terminal是否可用
        /// </summary>
        private bool IsWindowsTerminalAvailable()
        {
            try
            {
                ProcessStartInfo startInfo = new ProcessStartInfo
                {
                    FileName = "powershell.exe",
                    Arguments = "-Command " +
                               "try { Get-AppxPackage -Name '*WindowsTerminal*' -ErrorAction Stop; exit 0 } catch { exit 1 }",
                    UseShellExecute = false,
                    CreateNoWindow = true
                };

                using (Process process = Process.Start(startInfo))
                {
                    process.WaitForExit();
                    return process.ExitCode == 0;
                }
            }
            catch
            {
                return false;
            }
        }

        // 选择EXE文件
        private void SelectExeFile()
        {
            using var ofd = new OpenFileDialog
            {
                Filter = "Executable Files (*.exe)|*.exe|All Files (*.*)|*.*",
                Title = "选择可执行文件"
            };
            if (ofd.ShowDialog() == DialogResult.OK)
                _txtExePath.Text = ofd.FileName;
        }

        // 运行EXE文件
        private void RunExeFile()
        {
            if (string.IsNullOrWhiteSpace(_txtExePath.Text) || !File.Exists(_txtExePath.Text))
            {
                Log("⚠️ 请先选择有效的 EXE 文件");
                return;
            }
            bool useTerminal = _comboRunMode.SelectedIndex == 1;
            try
            {
                ProcessStartInfo psi;
                if (useTerminal && IsWindowsTerminalAvailable())
                {
                    psi = new ProcessStartInfo
                    {
                        FileName = "wt.exe",
                        Arguments = $"-w 0 cmd /c \"chcp {Console.OutputEncoding.CodePage} & \"{_txtExePath.Text}\" {_txtExeArgs.Text} & pause\"",
                        UseShellExecute = true
                    };
                }
                else
                {
                    psi = new ProcessStartInfo
                    {
                        FileName = _txtExePath.Text,
                        Arguments = _txtExeArgs.Text,
                        UseShellExecute = false,
                        WorkingDirectory = Path.GetDirectoryName(_txtExePath.Text)
                    };
                    psi.EnvironmentVariables["PYTHONIOENCODING"] = "utf-8";
                }

                Process.Start(psi);
                Log($"🚀 已启动 {Path.GetFileName(_txtExePath.Text)}（{_comboRunMode.Text}）");
            }
            catch (Exception ex)
            {
                Log($"❌ 运行EXE错误：{ex.Message}");
            }
        }
        #endregion

        #region 编码控制方法
        // 日志输出（优化显示BOM处理信息）
        private void Log(string message)
        {
            string line = $"[{DateTime.Now:HH:mm:ss}] {message}";
            Console.WriteLine(line);
            _logBox.AppendText(line + Environment.NewLine);
            _logBox.ScrollToCaret();
        }

        // 刷新当前编码显示
        private void RefreshCurrent()
        {
            uint cp = GetConsoleOutputCP();
            try
            {
                string encodingName = Encoding.GetEncoding((int)cp).EncodingName;
                _lblCurrent.Text = $"当前控制台编码：{cp} （{encodingName}）";
                _lblCurrent.AutoSize = true;
            }
            catch
            {
                _lblCurrent.Text = $"当前控制台编码：{cp}（未知编码）";
            }
        }

        // 设置编码
        private void SetCp(uint codePage)
        {
            try
            {
                bool inputSuccess = SetConsoleCP(codePage);
                bool outputSuccess = SetConsoleOutputCP(codePage);
                Console.OutputEncoding = Encoding.GetEncoding((int)codePage);
                Console.InputEncoding = Encoding.GetEncoding((int)codePage);

                if (!inputSuccess || !outputSuccess)
                {
                    Log($"⚠️ 编码设置不完全成功（错误码：{Marshal.GetLastWin32Error()}）");
                }

                if (_chkPermanent.Checked)
                {
                    using var key = Registry.CurrentUser.CreateSubKey(@"Console");
                    key?.SetValue("CodePage", codePage, RegistryValueKind.DWord);
                    Log($"📝 已写入注册表，新窗口默认使用编码 {codePage}");
                }

                RefreshCurrent();
                Log($"🔄 已切换控制台编码为：{codePage}");
                RunEncodingTest();
            }
            catch (Exception ex)
            {
                Log($"❌ 设置编码错误：{ex.Message}");
            }
        }

        // 还原默认编码
        private void RestoreDefault()
        {
            try
            {
                using var key = Registry.CurrentUser.OpenSubKey(@"Console", writable: true);
                if (key?.GetValue("CodePage") != null)
                {
                    key.DeleteValue("CodePage");
                    Log("🗑️ 已删除注册表中的编码设置");
                }

                uint defaultCp = GetSystemDefaultOemCodePage();
                SetConsoleCP(defaultCp);
                SetConsoleOutputCP(defaultCp);
                Console.OutputEncoding = Encoding.GetEncoding((int)defaultCp);
                Console.InputEncoding = Encoding.GetEncoding((int)defaultCp);

                RefreshCurrent();
                Log($"🔄 已还原默认编码：{defaultCp}");
                RunEncodingTest();
            }
            catch (Exception ex)
            {
                Log($"❌ 还原编码错误：{ex.Message}");
            }
        }

        // 编码测试输出
        private void RunEncodingTest()
        {
            Log("--------------------------------------------------");
            Log("编码测试输出：");
            Log("中文测试：你好，世界！");
            Log("英文测试：Hello, World!");
            Log("符号测试：① ② ③ 🌍 ✅ 🔥");
            Log("--------------------------------------------------");
        }
        #endregion
    }
}